//
// Created by casdon on 2024/8/1.
//

#ifndef CIOT_BLE_H
#define CIOT_BLE_H

#include "types.h"

#ifdef __cplusplus
extern "C" {
#endif

#define CIOT_GATTS_SERVICE_UUID_DEVINFO         0x180A
#define CIOT_GATTS_CHAR_UUID_DEV_BRAND          0x2A29
#define CIOT_GATTS_CHAR_UUID_DEV_MODEL          0x2A24

#define CIOT_GATTS_SERVICE_UUID_CIOT_MSG        0xCAD0
#define CIOT_GATTS_CHAR_UUID_CIOT_RECEIVE       0x6b44
#define CIOT_GATTS_CHAR_UUID_CIOT_SEND          0x6b64

#define CIOT_GATTS_SERVICE_UUID_DEVINFO_STR     "180A"
#define CIOT_GATTS_CHAR_UUID_DEV_BRAND_STR      "2A29"
#define CIOT_GATTS_CHAR_UUID_DEV_MODEL_STR      "2A24"

#define CIOT_GATTS_SERVICE_UUID_CIOT_MSG_STR    "CAD0"
#define CIOT_GATTS_CHAR_UUID_CIOT_RECEIVE_STR   "6B44"
#define CIOT_GATTS_CHAR_UUID_CIOT_SEND_STR      "6B64"

typedef struct ciot_ble_adv_context_t
{
    uint8_t adv_data[31];
    uint8_t adv_data_len;
    uint8_t rsp_data[31];
    uint8_t rsp_data_len;
} ciot_ble_adv_context;

typedef enum Ciot_ble_stack_event_e
{
    Ciot_ble_stack_ready = 0,
    Ciot_ble_stack_preparing = 1,
    Ciot_ble_stack_failed = 2,
    Ciot_ble_stack_adv_ok = 3,
    Ciot_ble_stack_adv_failed = 4,
    Ciot_ble_stack_connected = 5,
    Ciot_ble_stack_disconnected = 6,

    Ciot_ble_stack_MAX
} Ciot_ble_stack_event;

typedef void (*ciot_ble_stack_event_handler_fn)(Ciot_ble_stack_event event);

Ciot_res ciot_ble_set_stack_event_handler( ciot_ble_stack_event_handler_fn handler );

typedef struct ciot_ble_adapter_manager_t
{
    bool inited;
    CIOT_ADAPTER Ciot_res (* init)(void);
    CIOT_ADAPTER Ciot_res (* deinit)(void);

    CIOT_ADAPTER Ciot_res (* start_adv)( const ciot_ble_adv_context * adv );
    CIOT_ADAPTER Ciot_res (* update_adv)( const ciot_ble_adv_context * adv );
    CIOT_ADAPTER Ciot_res (* stop_adv)(void);
    CIOT_ADAPTER Ciot_res (* clear) (void);

    CIOT_EVENT   Ciot_res (* receive_data)( uint8_t * buf, uint16_t buf_len);
    CIOT_ADAPTER Ciot_res (* send_data)( uint8_t * msg, uint16_t msg_len);

    CIOT_ADAPTER Ciot_res (* active_device)(void);
    CIOT_ADAPTER Ciot_res (* clear_bonded_info)(void);
    CIOT_ADAPTER Ciot_res (* disconnect)(void);
    CIOT_ADAPTER Ciot_res (* disconnected)(void);
    CIOT_ADAPTER Ciot_res (* connected)(void);

    // Less than 64 char
    CIOT_ADAPTER Ciot_res (* set_localname)( char * name, uint8_t len );
    // Less than 10 char
    CIOT_ADAPTER Ciot_res (* set_short_localname)( char * shortname, uint8_t len );
    // localname / esp_device_name

    CIOT_ADAPTER    Ciot_res (* set_mtu)( uint16_t mtu );
    CIOT_ADAPTER    uint16_t (* get_mtu)(void);

    CIOT_ADAPTER    uint16_t (* get_conn_interval_ms)(void);

    CIOT_ADAPTER    Ciot_res (* flash_read_config)( uint8_t * buf, uint32_t len );
    CIOT_ADAPTER    Ciot_res (* flash_save_config)( const uint8_t * buf, uint32_t len );
    CIOT_ADAPTER    Ciot_res (* flash_erase_config)( uint8_t * buf, uint32_t len );

//    void(* stack_event_handler)( ciot_ble_stack_event_handler_fn handler );

} ciot_ble_adapter_manager;

extern Ciot_res ciot_porting_ble_init();

CIOT_API
Ciot_res ciot_ble_adapter_manager_reg( ciot_ble_adapter_manager * ble_adapter );

CIOT_API
const ciot_ble_adapter_manager * ciot_ble_adapter_manager_instance();

#define ciot_ble_reg(A) ciot_ble_adapter_manager_reg(A)
#define ciot_ble_mgr() ciot_ble_adapter_manager_instance()
#define ciot_ble() ciot_ble_mgr()

#ifdef __cplusplus
}
#endif

#endif //CIOT_BLE_H
